"""技术指标信号分析器主类.

提供技术指标信号分析的统一接口，支持单个指标分析、批量分析和组合分析。
"""

from __future__ import annotations

import logging
from typing import Any, Dict, List, Optional

import pandas as pd

from .combined_analyzer import CombinedIndicatorAnalyzer
from .single_analyzer import SingleIndicatorAnalyzer
from .thresholds import IndicatorThresholds
from .types import SignalDirection, SignalResult, SignalStrength
from .utils import extract_indicator_values, normalize_indicator_name

logger = logging.getLogger(__name__)

class IndicatorSignalAnalyzer:
    """技术指标信号分析器主类.
    
    提供技术指标信号分析的统一接口，支持单个指标分析、批量分析和组合分析。
    """
    
    def __init__(self, thresholds: Optional[IndicatorThresholds] = None):
        """初始化分析器.
        
        Parameters
        ----------
        thresholds : Optional[IndicatorThresholds], optional
            阈值配置对象，如果为None则使用默认阈值
        """
        self.thresholds = thresholds or IndicatorThresholds()
        self.single_analyzer = SingleIndicatorAnalyzer(self.thresholds)
        self.combined_analyzer = CombinedIndicatorAnalyzer()
    
    def analyze_single_indicator(self, indicator_name: str, value: Any, **kwargs) -> SignalResult:
        """分析单个指标.
        
        根据指标名称调用对应的判断函数。
        
        Parameters
        ----------
        indicator_name : str
            指标名称（如 "rsi_14", "macd_dif" 等）
        value : Any
            指标值（可以是单个数值或字典）
        **kwargs
            其他参数（如用于MACD的前一个值等）
            
        Returns
        -------
        SignalResult
            信号分析结果
        """
        normalized_name = normalize_indicator_name(indicator_name)
        
        try:
            if normalized_name == "rsi":
                return self.single_analyzer.analyze_rsi(value)
            elif normalized_name == "cmo":
                return self.single_analyzer.analyze_cmo(value)
            elif normalized_name == "kdj":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_kdj(
                        value.get("k"), value.get("d"), value.get("j"),
                        kwargs.get("prev_k"), kwargs.get("prev_d")
                    )
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "KDJ需要k、d、j三个值"},
                    )
            elif normalized_name == "williams_r":
                return self.single_analyzer.analyze_williams_r(value)
            elif normalized_name == "cci":
                return self.single_analyzer.analyze_cci(value)
            elif normalized_name == "mfi":
                return self.single_analyzer.analyze_mfi(value)
            elif normalized_name == "macd":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_macd(
                        value.get("dif"), value.get("dea"), value.get("hist"),
                        kwargs.get("prev_dif"), kwargs.get("prev_dea"), kwargs.get("prev_hist")
                    )
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "MACD需要dif、dea、hist三个值"},
                    )
            elif normalized_name == "adx":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_adx(
                        value.get("adx"), value.get("plus_di"), value.get("minus_di")
                    )
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "ADX需要adx、plus_di、minus_di三个值"},
                    )
            elif normalized_name == "bollinger":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_bollinger(
                        value.get("bb_position"), value.get("price"),
                        value.get("bb_upper"), value.get("bb_lower")
                    )
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "布林带需要bb_position值"},
                    )
            elif normalized_name == "price_percentile":
                return self.single_analyzer.analyze_price_percentile(value)
            elif normalized_name == "vwap":
                return self.single_analyzer.analyze_vwap_bias(value)
            elif normalized_name == "ma_system":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_ma_system(
                        value.get("sma5"), value.get("sma10"), value.get("sma20"),
                        value.get("ema5"), value.get("ema10"), value.get("ema20"),
                        value.get("price")
                    )
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "均线系统需要sma/ema和price值"},
                    )
            elif normalized_name == "trend_persistence":
                return self.single_analyzer.analyze_trend_persistence(value)
            elif normalized_name == "obv":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_obv(value.get("obv_ratio"), value.get("obv_trend"))
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "OBV需要obv_ratio值"},
                    )
            elif normalized_name == "candlestick_patterns":
                if isinstance(value, dict):
                    return self.single_analyzer.analyze_candlestick_patterns(value)
                else:
                    return SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.0,
                        value=value,
                        threshold_info={"reason": "K线形态需要patterns_dict"},
                    )
            else:
                # 不输出警告信息，静默处理未知指标类型
                # logger.warning(f"未知的指标类型: {indicator_name} (标准化后: {normalized_name})")
                return SignalResult(
                    direction=SignalDirection.NEUTRAL,
                    strength=SignalStrength.WEAK,
                    confidence=0.0,
                    value=value,
                    threshold_info={"reason": f"未知指标类型: {normalized_name}"},
                )
        except Exception as e:
            logger.error(f"分析指标 {indicator_name} 时出错: {e}")
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.0,
                value=value,
                threshold_info={"reason": f"分析出错: {str(e)}"},
            )
    
    def analyze_from_features(self, features: pd.DataFrame, latest_only: bool = True) -> pd.DataFrame:
        """从特征DataFrame中分析所有指标.
        
        从特征DataFrame中提取所有指标值，对每个指标进行判断。
        
        Parameters
        ----------
        features : pd.DataFrame
            特征DataFrame
        latest_only : bool, default True
            是否只分析最新一行的数据
            
        Returns
        -------
        pd.DataFrame
            包含所有指标判断结果的DataFrame
            列包括：indicator_name, direction, strength, confidence, value, threshold_info
        """
        # 提取指标值
        if latest_only:
            indicator_values = extract_indicator_values(features, latest_only=True)
            rows = []
            
            # 分析每个指标
            for indicator_name, value in indicator_values.items():
                result = self.analyze_single_indicator(indicator_name, value)
                rows.append({
                    "indicator_name": indicator_name,
                    "direction": result.direction.value,
                    "strength": result.strength.value,
                    "confidence": result.confidence,
                    "value": value,
                    "threshold_info": result.threshold_info,
                })
            
            return pd.DataFrame(rows)
        else:
            # 分析所有行
            all_results = []
            for idx in features.index:
                row_features = features.loc[[idx]]
                row_results = self.analyze_from_features(row_features, latest_only=True)
                row_results["timestamp"] = idx
                all_results.append(row_results)
            
            return pd.concat(all_results, ignore_index=True)
    
    def analyze_combinations(
        self,
        features: pd.DataFrame,
        combination_configs: Optional[List[Dict[str, Any]]] = None,
    ) -> pd.DataFrame:
        """分析指标组合.
        
        根据配置分析指标组合。
        
        Parameters
        ----------
        features : pd.DataFrame
            特征DataFrame
        combination_configs : Optional[List[Dict[str, Any]]], optional
            组合配置列表，每个配置包含组合类型和所需指标
            如果为None，则分析默认组合（趋势系统、动量系统、量价系统、综合系统）
            
        Returns
        -------
        pd.DataFrame
            组合判断结果DataFrame
        """
        if combination_configs is None:
            # 默认组合配置
            combination_configs = [
                {"name": "trend_system", "type": "trend"},
                {"name": "momentum_system", "type": "momentum"},
                {"name": "volume_price_system", "type": "volume_price"},
                {"name": "comprehensive_system", "type": "comprehensive"},
            ]
        
        # 先分析所有单个指标
        single_results = self.analyze_from_features(features, latest_only=True)
        single_results_dict = {}
        for _, row in single_results.iterrows():
            single_results_dict[row["indicator_name"]] = SignalResult(
                direction=SignalDirection(row["direction"]),
                strength=SignalStrength(row["strength"]),
                confidence=row["confidence"],
                value=row["value"],
                threshold_info=row["threshold_info"],
            )
        
        # 分析各个组合
        combination_results = []
        indicator_values = extract_indicator_values(features, latest_only=True)
        
        for config in combination_configs:
            combo_name = config.get("name", "unknown")
            combo_type = config.get("type", "unknown")
            
            if combo_type == "trend":
                # 趋势系统
                macd_result = None
                adx_result = None
                ma_result = None
                
                # 提取MACD
                if "macd_dif" in indicator_values and "macd_dea" in indicator_values and "macd_hist" in indicator_values:
                    macd_result = self.single_analyzer.analyze_macd(
                        indicator_values["macd_dif"],
                        indicator_values["macd_dea"],
                        indicator_values["macd_hist"],
                    )
                
                # 提取ADX
                if "adx" in indicator_values and "adx_plus_di" in indicator_values and "adx_minus_di" in indicator_values:
                    adx_result = self.single_analyzer.analyze_adx(
                        indicator_values["adx"],
                        indicator_values["adx_plus_di"],
                        indicator_values["adx_minus_di"],
                    )
                
                # 提取均线系统（需要价格，这里简化处理）
                if "sma_5" in indicator_values and "sma_20" in indicator_values:
                    # 简化：只使用SMA判断
                    ma_result = SignalResult(
                        direction=SignalDirection.NEUTRAL,
                        strength=SignalStrength.WEAK,
                        confidence=0.2,
                        value={"sma5": indicator_values.get("sma_5"), "sma20": indicator_values.get("sma_20")},
                        threshold_info={},
                    )
                
                result = self.combined_analyzer.analyze_trend_system(macd_result, adx_result, ma_result)
                
            elif combo_type == "momentum":
                # 动量系统
                rsi_result = single_results_dict.get("rsi_14")
                kdj_result = None
                if "kdj_k" in indicator_values and "kdj_d" in indicator_values:
                    kdj_result = self.single_analyzer.analyze_kdj(
                        indicator_values["kdj_k"],
                        indicator_values["kdj_d"],
                        indicator_values.get("kdj_j"),
                    )
                cci_result = single_results_dict.get("cci_20")
                
                result = self.combined_analyzer.analyze_momentum_system(rsi_result, kdj_result, cci_result)
                
            elif combo_type == "volume_price":
                # 量价系统
                obv_result = single_results_dict.get("obv_ratio")
                mfi_result = single_results_dict.get("mfi_14")
                volume_ratio = indicator_values.get("volume_ratio")
                
                result = self.combined_analyzer.analyze_volume_price_system(obv_result, mfi_result, volume_ratio)
                
            elif combo_type == "comprehensive":
                # 综合系统
                result = self.combined_analyzer.analyze_comprehensive_system(single_results_dict)
                
            else:
                result = SignalResult(
                    direction=SignalDirection.NEUTRAL,
                    strength=SignalStrength.WEAK,
                    confidence=0.0,
                    value={},
                    threshold_info={"reason": f"未知的组合类型: {combo_type}"},
                )
            
            combination_results.append({
                "combination_name": combo_name,
                "combination_type": combo_type,
                "direction": result.direction.value,
                "strength": result.strength.value,
                "confidence": result.confidence,
                "value": result.value,
                "threshold_info": result.threshold_info,
            })
        
        return pd.DataFrame(combination_results)
    
    def get_summary(self, features: pd.DataFrame) -> Dict[str, Any]:
        """汇总所有指标的判断结果.
        
        Parameters
        ----------
        features : pd.DataFrame
            特征DataFrame
            
        Returns
        -------
        Dict[str, Any]
            汇总信息，包括：
            - bullish_count: 看多指标数量
            - bearish_count: 看空指标数量
            - neutral_count: 中性指标数量
            - avg_confidence: 平均置信度
            - strong_signals: 强烈信号列表
            - main_signals: 主要信号（看多/看空/中性）
        """
        results = self.analyze_from_features(features, latest_only=True)
        
        bullish_count = len(results[results["direction"] == "看多"])
        bearish_count = len(results[results["direction"] == "看空"])
        neutral_count = len(results[results["direction"] == "中性"])
        
        avg_confidence = results["confidence"].mean() if len(results) > 0 else 0.0
        
        strong_signals = results[
            (results["strength"] == "强烈") & (results["confidence"] > 0.7)
        ][["indicator_name", "direction", "confidence"]].to_dict("records")
        
        # 判断主要信号
        if bullish_count > bearish_count and bullish_count > neutral_count:
            main_signal = "看多"
        elif bearish_count > bullish_count and bearish_count > neutral_count:
            main_signal = "看空"
        else:
            main_signal = "中性"
        
        return {
            "bullish_count": bullish_count,
            "bearish_count": bearish_count,
            "neutral_count": neutral_count,
            "total_count": len(results),
            "avg_confidence": avg_confidence,
            "strong_signals": strong_signals,
            "main_signal": main_signal,
        }


def _is_supported_indicator(indicator_name: str) -> bool:
    """检查指标是否被支持.
    
    通过标准化指标名称，检查是否在analyze_single_indicator方法中有对应的处理逻辑。
    
    Parameters
    ----------
    indicator_name : str
        指标名称
        
    Returns
    -------
    bool
        如果指标被支持则返回True，否则返回False
    """
    normalized = normalize_indicator_name(indicator_name)
    # 定义支持的技术指标类型列表
    # 这些是在analyze_single_indicator方法中实际处理的指标类型
    supported_types = {
        "rsi", "cmo", "kdj", "williams_r", "cci", "mfi", "macd",
        "adx", "bollinger", "price_percentile", "vwap", "ma_system",
        "trend_persistence", "obv", "candlestick_patterns"
    }
    return normalized in supported_types


def main(symbol: str = "515790", limit: int = 500) -> None:
    """主函数：使用真实数据测试信号分析器.
    
    从ETF历史数据中提取特征，分析所有技术指标信号，并以表格形式输出结果。
    
    Parameters
    ----------
    symbol : str, default "515790"
        ETF代码，例如 "159919"（沪深300ETF）或 "515790"（光伏ETF）
    limit : int, default 500
        获取的历史数据条数，默认500条
    """
    import sys
    import argparse
    from pathlib import Path
    
    # 添加项目根目录到路径，以便导入其他模块
    project_root = Path(__file__).parent.parent.parent
    if str(project_root) not in sys.path:
        sys.path.insert(0, str(project_root))
    
    # 导入必要的模块
    from src.data import fetch_etf_history
    from src.features.pipeline import build_feature_dataframe
    
    print("=" * 80)
    print("技术指标信号分析器测试")
    print("=" * 80)
    print(f"\n正在获取 ETF 数据: {symbol}")
    
    try:
        # 1. 获取ETF历史数据
        # fetch_etf_history 函数会返回 ETFHistoricalDataset 对象
        # 其中包含 frame（DataFrame）和 metadata（元数据）等属性
        dataset = fetch_etf_history(symbol, limit=limit)  # 获取指定数量的历史数据
        print(f"✓ 数据获取成功: {dataset.symbol}")
        print(f"  - 数据量: {dataset.count} 条")
        print(f"  - 时间范围: {dataset.start.date()} 至 {dataset.end.date()}")
        
        if dataset.metadata and dataset.metadata.name:
            print(f"  - ETF名称: {dataset.metadata.name}")
        
        # 2. 生成特征数据
        # build_feature_dataframe 函数从原始OHLCV数据中提取技术指标特征
        # 返回的DataFrame包含各种技术指标列，如 rsi_14, macd_dif, kdj_k 等
        print(f"\n正在生成特征数据...")
        features = build_feature_dataframe(dataset.frame)
        print(f"✓ 特征生成完成: {len(features)} 行 × {len(features.columns)} 列")
        
        # 3. 创建信号分析器
        # IndicatorSignalAnalyzer 是主分析器类，用于分析技术指标信号
        analyzer = IndicatorSignalAnalyzer()
        
        # 4. 分析所有指标
        # analyze_from_features 方法会从特征DataFrame中提取所有指标值并进行分析
        # 返回一个DataFrame，包含每个指标的分析结果（方向、强度、置信度等）
        # 为了减少警告信息，我们只分析支持的技术指标
        print(f"\n正在分析技术指标信号...")
        
        # 临时禁用警告，只分析支持的技术指标
        import warnings
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore", category=UserWarning)
            # 先过滤出支持的技术指标
            supported_indicators = [col for col in features.columns if _is_supported_indicator(col)]
            print(f"  发现 {len(supported_indicators)} 个支持的技术指标")
            
            # 只分析支持的技术指标
            if supported_indicators:
                # 创建一个只包含支持指标的特征DataFrame
                filtered_features = features[supported_indicators]
                results = analyzer.analyze_from_features(filtered_features, latest_only=True)
            else:
                # 如果没有支持的技术指标，使用全部特征（会显示警告）
                results = analyzer.analyze_from_features(features, latest_only=True)
        
        print(f"✓ 分析完成: 共 {len(results)} 个指标")
        
        # 5. 格式化输出表格
        # 将分析结果按照看多、看空、中性分类，并以表格形式展示
        print("\n" + "=" * 80)
        print("技术指标信号分析结果")
        print("=" * 80)
        
        # 按方向分组统计
        bullish_results = results[results["direction"] == "看多"].copy()
        bearish_results = results[results["direction"] == "看空"].copy()
        neutral_results = results[results["direction"] == "中性"].copy()
        
        # 格式化指标值显示
        def format_value(val):
            """格式化指标值显示."""
            if isinstance(val, dict):
                # 如果是字典（如MACD、KDJ等），显示主要值
                if "dif" in val:
                    return f"DIF:{val.get('dif', 0):.4f}"
                elif "k" in val:
                    return f"K:{val.get('k', 0):.2f}"
                elif "bb_position" in val:
                    return f"位置:{val.get('bb_position', 0):.2f}"
                else:
                    return str(val)[:30]  # 截断过长的字符串
            elif isinstance(val, (int, float)):
                return f"{val:.4f}"
            else:
                return str(val)[:30]
        
        # 输出看多信号表格
        print("\n【看多信号】")
        if len(bullish_results) > 0:
            # 按置信度降序排列
            bullish_sorted = bullish_results.sort_values("confidence", ascending=False)
            
            # 创建输出表格数据
            table_data = []
            for _, row in bullish_sorted.iterrows():
                table_data.append({
                    "指标名称": row["indicator_name"],
                    "信号强度": row["strength"],
                    "置信度": f"{row['confidence']:.2%}",
                    "指标值": format_value(row["value"]),
                })
            
            # 使用pandas DataFrame格式化输出表格
            output_df = pd.DataFrame(table_data)
            print(output_df.to_string(index=False))
            print(f"\n总计: {len(bullish_results)} 个看多信号")
        else:
            print("  无看多信号")
        
        # 输出看空信号表格
        print("\n【看空信号】")
        if len(bearish_results) > 0:
            # 按置信度降序排列
            bearish_sorted = bearish_results.sort_values("confidence", ascending=False)
            
            # 创建输出表格数据
            table_data = []
            for _, row in bearish_sorted.iterrows():
                table_data.append({
                    "指标名称": row["indicator_name"],
                    "信号强度": row["strength"],
                    "置信度": f"{row['confidence']:.2%}",
                    "指标值": format_value(row["value"]),
                })
            
            # 使用pandas DataFrame格式化输出表格
            output_df = pd.DataFrame(table_data)
            print(output_df.to_string(index=False))
            print(f"\n总计: {len(bearish_results)} 个看空信号")
        else:
            print("  无看空信号")
        
        # 输出中性信号统计
        print("\n【中性信号】")
        print(f"  总计: {len(neutral_results)} 个中性信号")
        if len(neutral_results) > 0:
            neutral_names = neutral_results["indicator_name"].tolist()
            print(f"  指标列表: {', '.join(neutral_names[:10])}")
            if len(neutral_names) > 10:
                print(f"  ... 还有 {len(neutral_names) - 10} 个指标")
        
        # 输出汇总统计
        print("\n" + "=" * 80)
        print("汇总统计")
        print("=" * 80)
        summary = analyzer.get_summary(features)
        print(f"看多指标数量: {summary['bullish_count']}")
        print(f"看空指标数量: {summary['bearish_count']}")
        print(f"中性指标数量: {summary['neutral_count']}")
        print(f"总指标数量: {summary['total_count']}")
        print(f"平均置信度: {summary['avg_confidence']:.2%}")
        print(f"主要信号: {summary['main_signal']}")
        
        # 输出强烈信号
        if summary['strong_signals']:
            print("\n强烈信号（置信度 > 70%）:")
            for signal in summary['strong_signals']:
                print(f"  - {signal['indicator_name']}: {signal['direction']} "
                      f"(置信度: {signal['confidence']:.2%})")
        
        print("\n" + "=" * 80)
        print("测试完成！")
        print("=" * 80)
        
    except Exception as e:
        logger.error(f"测试执行失败: {e}", exc_info=True)
        print(f"\n❌ 测试失败: {e}")
        import traceback
        traceback.print_exc()
        raise


if __name__ == "__main__":
    import argparse
    
    # 创建命令行参数解析器
    # argparse 是Python标准库，用于解析命令行参数
    parser = argparse.ArgumentParser(
        description="技术指标信号分析器 - 分析ETF的技术指标信号",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例用法:
  # 使用默认ETF代码（515790）
  python -m src.signals.analyzer
  
  # 指定ETF代码
  python -m src.signals.analyzer --symbol 159919
  
  # 指定ETF代码和数据条数
  python -m src.signals.analyzer --symbol 159919 --limit 1000
        """
    )
    
    # 添加命令行参数
    # --symbol 或 -s: ETF代码参数
    parser.add_argument(
        "--symbol", "-s",
        type=str,
        default="515790",
        help="ETF代码，例如 159919（沪深300ETF）或 515790（光伏ETF），默认: 515790"
    )
    
    # --limit 或 -l: 数据条数参数
    parser.add_argument(
        "--limit", "-l",
        type=int,
        default=500,
        help="获取的历史数据条数，默认: 500"
    )
    
    # 解析命令行参数
    # parse_args() 会解析命令行传入的参数，返回一个包含所有参数值的对象
    args = parser.parse_args()
    
    # 调用main函数，传入解析得到的参数
    # args.symbol 和 args.limit 是从命令行参数中解析得到的值
    main(symbol=args.symbol, limit=args.limit)
